package com.joe.demo.chat.protocol;

import com.joe.demo.chat.config.Config;
import com.joe.demo.chat.message.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * @Description 编解码, 必须和LengthFieldBasedFrameDecoder 一起使用，保证消息完整
 * @Author gaojw
 * @Date 2024-08-30
 */
@Slf4j
@ChannelHandler.Sharable
public class MessageCodecSharable extends MessageToMessageCodec<ByteBuf, Message> {

    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, Message message, List<Object> list) throws Exception {
        final ByteBuf byteBuf = channelHandlerContext.alloc().buffer();
        // 4 字节 魔数
        byteBuf.writeBytes(new byte[]{1,2,3,4});
        // 1 字节 版本
        byteBuf.writeByte(1);
        // 1 字节 序列化的方式 jdk 0 json 1
        byteBuf.writeByte(Config.getSerializerAlgorithm().ordinal());
        // 1 字节 指令类型
        byteBuf.writeByte(message.getMessageType());
        // 4 字节 请求序号
        byteBuf.writeInt(message.getSequenceId());
        // 无意义， 对齐填充
        byteBuf.writeByte(0xff);

        final byte[] bytes = Config.getSerializerAlgorithm().serializer(message);
        // 4 字节 长度
        byteBuf.writeInt(bytes.length);
        // 获取内容的字节数组
        byteBuf.writeBytes(bytes);
        list.add(byteBuf);
    }

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        final int magicNum = byteBuf.readInt();
        final byte version = byteBuf.readByte();
        final byte serializerType = byteBuf.readByte();
        final byte messageType = byteBuf.readByte();
        final int sequenceId = byteBuf.readInt();
        byteBuf.readByte();
        final int contentLength = byteBuf.readInt();

        final byte[] bytes = new byte[contentLength];
        byteBuf.readBytes(bytes, 0, contentLength);
        // 找到反序列化时的算法
        final Serializer.Algorithm algorithm = Serializer.Algorithm.values()[serializerType];
        // 确定具体消息类型
        Class<? extends Message> messageClass = Message.getMessageClass(messageType);
        final Message message = algorithm.deserializer(messageClass, bytes);
        log.info("{}, {}, {}, {}, {}, {}", magicNum, version, serializerType, messageType, sequenceId, contentLength);
        log.info("{}", message);
        list.add(message);

    }
}
